let utils = {
    tree: {
        remove(src, rm) {
            if (rm) src.parent.children.splice(src.i, 1);
        },
        top(src, dst, rm) {
            utils.init(src.node);
            if (src.i > dst.i) {
                if (rm) src.parent.children.splice(src.i, 1);
                dst.parent.children.splice(dst.i, 0, src.node);
            } else {
                dst.parent.children.splice(dst.i, 0, src.node);
                if (rm) src.parent.children.splice(src.i, 1);
            }
        },
        center(src, dst, rm) {
            utils.init(src.node);
            if (rm) src.parent.children.splice(src.i, 1);
            if (typeof dst.node.children === 'string') utils.Vue.set(dst.node, 'children', [dst.node.children, src.node]);
            else if (dst.node.children) dst.node.children.push(src.node);
            else utils.Vue.set(dst.node, 'children', [src.node]);
        },
        bottom(src, dst, rm) {
            utils.init(src.node);
            if (src.i > dst.i) {
                if (rm) src.parent.children.splice(src.i, 1);
                dst.parent.children.splice(dst.i + 1, 0, src.node);
            } else {
                dst.parent.children.splice(dst.i + 1, 0, src.node);
                if (rm) src.parent.children.splice(src.i, 1);
            }
        },
        /**
         * 通过path来获取结点
         * @param {any} tree
         * @param {stirng} path /1/2/3/
         */
        getNode(tree, path) {
            var node = tree;
            if (path.length < 3) return { parent: { children: [] }, i: 0, node };
            let ss = path.slice(1, -1).split('/');
            let i = +ss.pop();
            for (let s of ss) {
                if (node instanceof Array) node = node[s];
                else node = node.children[s];
            }
            return { parent: node, i, node: node.children[i] };
        },
        clone(node, all) {
            if (typeof node != "object") return node;
            if (node instanceof Array) {
                return node.map(x => this.clone(x, all));
            }
            let dst = {};
            for (let k in node) {
                if (all || ['i', 'key', 'parent', 'children'].indexOf(k) < 0) {
                    dst[k] = this.clone(node[k], true);
                }
            }
            if (node.children)
                dst.children = this.clone(node.children);
            return dst;
        },
        clear(node) {
            node = node;
            if (!node) return;
            if (node instanceof Array) {
                for (let item of node) {
                    this.clear(item);
                }
                return;
            }
            delete node.i;
            delete node.key;
            delete node.parent;
            this.clear(node.children);
        }
    },
    /**
     * 组件名转组件url
     * @param {string} name 
     */
    toURL(name) {
        return '../dist/' + name + '.js';
    },
    store: {
        drag: null, // drag对象
        drag_move: null, // drop后删除
        move: null, // 拖动元素
        move_node: null, // 拖动节点
        move_begin: [0, 0, 0, 0], // 鼠标、元素拖动开始位置
    },
    status: {}, // 组件加载状态, 0: 失败 1:加载中 2:已加载
    loading: {}, // 加载中的组件
    loaded: {}, // 加载成功的组件
    /**
     * 获取组件
     * @param {string} name 
     */
    get(name) {
        return utils.loaded[name];
    },
    init(node, comp) {
        if (node.inited) return;
        if (!comp) comp = utils.get[node.name];
        if (comp) {
            if (comp.props) {
                if (!node.props) node.props = {};
                for (let k in comp.props) {
                    if (!node.props[k]) {
                        let v = comp.props[k];
                        if (typeof v.default === 'function') node.props[k] = v.default();
                        else node.props[k] = v.default;
                    }
                }
            }
            if (node.style) Object.defineProperty(node, 'style', { configurable: false });
            Object.defineProperty(node, 'inited', { configurable: false, value: true, enumerable: false });
        } else if (/^[A-Z]/.test(node.name))
            return utils.load(node.name).then(comp => {
                utils.init(node, comp);
                return comp;
            });
    },
    load(name) {
        if (utils.loading[name]) return utils.loading[name];
        return utils.loading[name] = new Promise((resolve, reject) => {
            var script = document.createElement('script');
            script.src = utils.toURL(name);
            document.head.appendChild(script);
            script.onload = function() {
                console.log(name, 'ok');
                let comp = window[name];
                comp = comp.default || comp;
                utils.loaded[name] = comp;
                utils.Vue.component(name, comp);
                resolve(comp);
            };
            script.onerror = reject;
        });
    },
    /**
     * 载入树中用到的组件
     * @param {any} tree 
     */
    loadAll(tree) {
        let pms = [];

        function dfs(node) {
            if (!node) return;
            if (node instanceof Array) {
                for (let item of node) {
                    dfs(item);
                }
                return;
            }
            if (!node.name) return;
            let p = utils.init(node);
            if (p) pms.push(p);
            dfs(node.children);
        }
        dfs(tree);
        return Promise.all(pms);
    },
    /**
     * 当前鼠标相对元素的位置
     * @param {MouseEvent} e 
     * @param {DOMRect} [rect] 
     */
    mousePosition(e, rect) {
        rect = rect || e.target.getClientRects()[0];
        let p = (e.pageY - rect.top) / rect.height;
        // console.log(e.pageY, rect.top, rect.height, p);
        if (p < 0.3) return 'top';
        if (p < 0.7) return 'center';
        return 'bottom';
    },
    /**
     * 
     * @param {HTMLElement} div 移动目标
     * @param {MouseEvent} e 
     * @param {string} [pos] 添加class
     * @param {HTMLElement} [container] 移动位置相对元素
     */
    move(div, e, pos, container) {
        if (e) {
            let r0 = container ? container.getClientRects()[0] : { top: 0, left: 0 };
            let rect = e.target.getClientRects()[0];
            div.style.top = rect.top - r0.top + 1 + 'px';
            div.style.left = rect.left - r0.left + 1 + 'px';
            div.style.width = rect.width - 2 + 'px';
            div.style.height = rect.height - 2 + 'px';
            if (!pos) pos = utils.mousePosition(e, rect);
        }
        if (pos) {
            utils.setCls(div, pos);
        }
    },
    setCls(div, pos) {
        var cls = div.className.split(' ').slice(0, -1);
        cls.push(pos);
        div.className = cls.join(' ');
    },
    addCls(div, pos) {
        var cls = div.className.split(' ');
        if (cls.indexOf(pos) < 0) {
            cls.push(pos);
            div.className = cls.join(' ');
        }
    },
    delCls(div, pos) {
        var cls = div.className.split(' ');
        var i = cls.indexOf(pos);
        if (i >= 0) {
            cls.splice(i, 1);
            div.className = cls.join(' ');
        }
    }
};
window.utils = utils;
export default utils;